<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="rF4tf" id="rF4tf"><span data-lake-id="u169a12f3" id="u169a12f3">典型回答</span></h1>
  <p data-lake-id="uf1104d5d" id="uf1104d5d"><br></p>
  <p data-lake-id="u559a451a" id="u559a451a"><span data-lake-id="u01db5e25" id="u01db5e25">存储过程是一种在数据库中存储的预编译的代码块，它可以执行一系列的数据库操作。存储过程被设计用来完成特定的功能或业务逻辑，通常是一组SQL语句的集合。</span></p>
  <p data-lake-id="ued8e8bdd" id="ued8e8bdd"><span data-lake-id="u2a48ca19" id="u2a48ca19">​</span><br></p>
  <p data-lake-id="ua32f8399" id="ua32f8399"><span data-lake-id="ud1b0043e" id="ud1b0043e">假设我们有一个名为 Employees 的数据库表，其中包含员工的基本信息，如员工ID、姓名和薪水。我们想创建一个存储过程来更新特定员工的薪水。以下是一个在MySQL中实现这个功能的存储过程示例：</span></p>
  <p data-lake-id="u1def2248" id="u1def2248"><span data-lake-id="ubf7c1f4c" id="ubf7c1f4c">​</span><br></p>
  <pre lang="java"><code>
DELIMITER //

CREATE PROCEDURE UpdateEmployeeSalary(IN empID INT, IN newSalary DECIMAL(10,2))
BEGIN
    -- 检查新薪水是否大于0
    IF newSalary &gt; 0 THEN
        -- 更新员工的薪水
        UPDATE Employees SET salary = newSalary WHERE employee_id = empID;
    ELSE
        -- 如果薪水无效，则抛出错误
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Invalid salary amount';
    END IF;
END //

DELIMITER ;

</code></pre>
  <p data-lake-id="u63f91168" id="u63f91168"><span data-lake-id="uc3134a00" id="uc3134a00">​</span><br></p>
  <p data-lake-id="udeee6335" id="udeee6335"><span data-lake-id="u0991b5f5" id="u0991b5f5">这个存储过程名为 UpdateEmployeeSalary，接受两个参数：empID（员工ID）和 newSalary（新薪水）。它首先检查新薪水是否为正数，如果是，则更新对应员工的薪水。如果薪水不合理（例如，小于或等于0），则抛出一个错误。</span></p>
  <p data-lake-id="uad43220f" id="uad43220f"><span data-lake-id="ucb557787" id="ucb557787">​</span><br></p>
  <p data-lake-id="u8119495f" id="u8119495f"><span data-lake-id="u05e64137" id="u05e64137" class="lake-fontsize-12" style="color: rgb(55, 65, 81)">要调用这个存储过程，可以使用以下SQL命令：</span></p>
  <p data-lake-id="u00448c0a" id="u00448c0a"><span data-lake-id="u0c90d827" id="u0c90d827" class="lake-fontsize-12" style="color: rgb(55, 65, 81)">​</span><br></p>
  <pre lang="java"><code>
CALL UpdateEmployeeSalary(123, 50000.00);
</code></pre>
  <p data-lake-id="udafd7bca" id="udafd7bca"><br></p>
  <p data-lake-id="u56113ddb" id="u56113ddb"><span data-lake-id="u800d47f0" id="u800d47f0" class="lake-fontsize-12">但是，其实在现在的很多大型互联网应用中，</span><strong><span data-lake-id="ud6fa26c7" id="ud6fa26c7" class="lake-fontsize-12">存储过程用的已经非常少了。</span></strong><span data-lake-id="uef7ce635" id="uef7ce635" class="lake-fontsize-12">拿我自己来说，我其实从来都没有在生产环境中真正的使用过存储过程。</span></p>
  <p data-lake-id="ueed6dfb0" id="ueed6dfb0"><span data-lake-id="ua08be108" id="ua08be108" class="lake-fontsize-12">​</span><br></p>
  <p data-lake-id="ue5fe7648" id="ue5fe7648"><span data-lake-id="u05c50092" id="u05c50092">之所以很少用，是因为存储过程存在以下几个问题或者局限性：</span></p>
  <p data-lake-id="u04cfffb0" id="u04cfffb0"><span data-lake-id="u3be66c24" id="u3be66c24">​</span><br></p>
  <ol list="uc872206b">
   <li fid="u5b79951e" data-lake-id="u03e9715d" id="u03e9715d"><strong><span data-lake-id="u09e9fe88" id="u09e9fe88">可维护性</span></strong><span data-lake-id="u694e08e7" id="u694e08e7">：存储过程的逻辑可能是非常复杂的，随着内容的不断修改，会变的难以理解和维护。</span></li>
   <li fid="u5b79951e" data-lake-id="u45f62075" id="u45f62075"><strong><span data-lake-id="uaa3123d3" id="uaa3123d3">调试和测试困难</span></strong><span data-lake-id="u19cca59a" id="u19cca59a">：与应用程序代码相比，存储过程的调试和测试是非常困难的。他不像业务代码一样我们可以打日志、加断点、写单测等进行非常方便的调试。</span></li>
   <li fid="u5b79951e" data-lake-id="u2b5d9a7a" id="u2b5d9a7a"><strong><span data-lake-id="ue4e628ec" id="ue4e628ec">跨数据库兼容性</span></strong><span data-lake-id="u8827156a" id="u8827156a">：存储过程通常不是跨数据库平台兼容的。这意味着如果你从一个数据库系统（如MySQL）迁移到另一个（如PostgreSQL），可能需要重写所有存储过程。这会导致迁移工作量增加，并增加对特定数据库的依赖。</span></li>
   <li fid="u5b79951e" data-lake-id="ud838b9e9" id="ud838b9e9"><strong><span data-lake-id="ud25e88a6" id="ud25e88a6">容易出错</span></strong><span data-lake-id="ue70592e3" id="ue70592e3">：用到存储过程的场景，都是非常复杂的业务场景，里面会有很多很多业务逻辑，这些业务逻辑在存储过程中通过各种IF-ELSE分支来实现的话，非常容易出错。</span></li>
   <li fid="u5b79951e" data-lake-id="ud7b2f093" id="ud7b2f093"><strong><span data-lake-id="ub3554845" id="ub3554845">安全性问题</span></strong><span data-lake-id="u93d78496" id="u93d78496">：存储过程可能成为安全风险的源头，特别是如果它们不正确地处理输入数据，可能导致SQL注入等安全漏洞。此外，过度依赖存储过程可能会导致数据库权限和访问控制变得复杂。</span></li>
   <li fid="u5b79951e" data-lake-id="u44c5bb10" id="u44c5bb10"><strong><span data-lake-id="u056d551c" id="u056d551c">版本控制和源代码管理</span></strong><span data-lake-id="uf985121b" id="uf985121b">：存储过程的代码通常存储在数据库中，这可能使得将它们纳入常规的源代码管理和版本控制流程变得更加困难。</span></li>
   <li fid="u5b79951e" data-lake-id="ua5bd14f2" id="ua5bd14f2"><strong><span data-lake-id="u15e3b613" id="u15e3b613">代码审查</span></strong><span data-lake-id="u488a0611" id="u488a0611">：如果是业务逻辑写在代码中，很多时候CodeReview的时候都会非常重点的关注，但是对于SQL语句，有的时候就很容易被忽略，那么很多问题就不容易被暴露出来。</span></li>
  </ol>
  <p data-lake-id="u888d2f4f" id="u888d2f4f"><br></p>
  <p data-lake-id="u0e2128ba" id="u0e2128ba"><span data-lake-id="u800c6f6a" id="u800c6f6a">一般来说，比较常见的做法是不使用存储过程，而是直接在应用程序中实现业务逻辑。这可以通过任何服务器端编程语言完成。这种方式提高了代码的可移植性和可维护性，因为应用程序代码通常更易于管理和部署。</span></p>
 </body>
</html>